// gps_simulator/main.go
package main

import (
	"encoding/binary"
	"fmt"
	"log"
	"math"
	"math/rand"
	"net"
	"os"
	"os/signal"
	"sync"
	"syscall"
	"time"
)

// ============================ 数据结构定义 ============================

// Location 位置信息
type Location struct {
	Latitude  float64
	Longitude float64
	Speed     float64
	Direction float64
	Timestamp time.Time
}

// GPSDeviceSimulator GPS设备模拟器
type GPSDeviceSimulator struct {
	TerminalID      string
	VehicleID       string
	Manufacturer    string
	ServerAddr      string
	Conn            net.Conn
	IsConnected     bool
	CurrentLocation Location
}

// JT808MessageBuilder JT808协议消息构建器
type JT808MessageBuilder struct {
	terminalPhone string
	messageSerial uint16
}

// SimulatorManager 模拟器管理器
type SimulatorManager struct {
	simulators map[string]*GPSDeviceSimulator
	mu         sync.RWMutex
}

// ============================ 消息构建器实现 ============================

// NewJT808MessageBuilder 创建消息构建器
func NewJT808MessageBuilder(terminalPhone string) *JT808MessageBuilder {
	return &JT808MessageBuilder{
		terminalPhone: terminalPhone,
		messageSerial: 1,
	}
}

// BuildLocationMessage 构建位置汇报消息 (0x0200)
func (b *JT808MessageBuilder) BuildLocationMessage(loc Location, alarmFlag uint32, statusFlag uint32) []byte {
	// 消息头
	header := b.buildHeader(0x0200, 28) // 基本位置信息28字节

	// 消息体
	body := make([]byte, 28)

	// 报警标志 (4字节)
	binary.BigEndian.PutUint32(body[0:4], alarmFlag)

	// 状态标志 (4字节)
	binary.BigEndian.PutUint32(body[4:8], statusFlag)

	// 纬度 (4字节)
	lat := uint32(math.Abs(loc.Latitude) * 1000000)
	if loc.Latitude < 0 {
		lat = 0x80000000 | lat // 最高位为1表示南纬
	}
	binary.BigEndian.PutUint32(body[8:12], lat)

	// 经度 (4字节)
	lon := uint32(math.Abs(loc.Longitude) * 1000000)
	if loc.Longitude < 0 {
		lon = 0x80000000 | lon // 最高位为1表示西经
	}
	binary.BigEndian.PutUint32(body[12:16], lon)

	// 高程 (2字节)
	altitude := uint16(50 + rand.Intn(100)) // 模拟高程50-150米
	binary.BigEndian.PutUint16(body[16:18], altitude)

	// 速度 (2字节)
	speed := uint16(loc.Speed * 10) // 0.1km/h为单位
	binary.BigEndian.PutUint16(body[18:20], speed)

	// 方向 (2字节)
	direction := uint16(loc.Direction)
	binary.BigEndian.PutUint16(body[20:22], direction)

	// 时间 (6字节 BCD码)
	timeBytes := b.timeToBCD(loc.Timestamp)
	copy(body[22:28], timeBytes)

	return b.assembleMessage(header, body)
}

// BuildRegisterMessage 构建终端注册消息 (0x0100)
func (b *JT808MessageBuilder) BuildRegisterMessage(manufacturerID string, deviceModel string) []byte {
	header := b.buildHeader(0x0100, 0)

	// 消息体：省域ID(2) + 市县域ID(2) + 制造商ID(5) + 终端型号(20) + 终端ID(7) + 车牌颜色(1) + 车牌号(不定)
	provinceID := uint16(44) // 广东省
	cityID := uint16(1)      // 广州市

	body := make([]byte, 2+2+5+20+7+1+10) // 预留空间

	// 省域ID
	binary.BigEndian.PutUint16(body[0:2], provinceID)

	// 市县域ID
	binary.BigEndian.PutUint16(body[2:4], cityID)

	// 制造商ID (5字节)
	copy(body[4:9], b.padString(manufacturerID, 5))

	// 终端型号 (20字节)
	copy(body[9:29], b.padString(deviceModel, 20))

	// 终端ID (7字节)
	copy(body[29:36], b.padString(b.terminalPhone, 7))

	// 车牌颜色 (1字节)
	body[36] = 1 // 蓝色

	// 车牌号 (变长)
	plateNumber := "粤A" + fmt.Sprintf("%05d", rand.Intn(100000))
	plateBytes := []byte(plateNumber)
	body[37] = byte(len(plateBytes))
	copy(body[38:38+len(plateBytes)], plateBytes)

	// 调整body长度
	body = body[:38+len(plateBytes)]

	// 更新消息头中的消息体长度
	header[2] = byte(len(body) >> 8)
	header[3] = byte(len(body))

	return b.assembleMessage(header, body)
}

// BuildHeartbeatMessage 构建心跳消息 (0x0002)
func (b *JT808MessageBuilder) BuildHeartbeatMessage() []byte {
	header := b.buildHeader(0x0002, 0)
	return b.assembleMessage(header, nil)
}

// 辅助方法
func (b *JT808MessageBuilder) buildHeader(messageID uint16, bodyLength int) []byte {
	header := make([]byte, 12)

	// 消息ID (2字节)
	binary.BigEndian.PutUint16(header[0:2], messageID)

	// 消息体属性 (2字节)
	bodyAttr := uint16(bodyLength) & 0x3FF // 低10位表示长度
	binary.BigEndian.PutUint16(header[2:4], bodyAttr)

	// 终端手机号 (6字节)
	copy(header[4:10], b.padString(b.terminalPhone, 6))

	// 消息流水号 (2字节)
	serial := b.messageSerial
	b.messageSerial++
	binary.BigEndian.PutUint16(header[10:12], serial)

	return header
}

func (b *JT808MessageBuilder) assembleMessage(header, body []byte) []byte {
	message := make([]byte, 0)
	message = append(message, 0x7E) // 起始符

	// 合并头和体
	data := append(header, body...)

	// 计算校验码 (异或校验)
	checksum := byte(0)
	for _, bt := range data {
		checksum ^= bt
	}

	// 转义处理
	escapedData := b.escapeData(data)
	message = append(message, escapedData...)

	// 添加校验码并转义
	escapedChecksum := b.escapeByte(checksum)
	message = append(message, escapedChecksum...)

	message = append(message, 0x7E) // 终止符
	return message
}

func (b *JT808MessageBuilder) escapeData(data []byte) []byte {
	result := make([]byte, 0)
	for _, bt := range data {
		result = append(result, b.escapeByte(bt)...)
	}
	return result
}

// 修复：escapeByte应该是JT808MessageBuilder的方法，不是byte的方法
func (b *JT808MessageBuilder) escapeByte(bt byte) []byte {
	switch bt {
	case 0x7E:
		return []byte{0x7D, 0x02}
	case 0x7D:
		return []byte{0x7D, 0x01}
	default:
		return []byte{bt}
	}
}

func (b *JT808MessageBuilder) timeToBCD(t time.Time) []byte {
	bytes := make([]byte, 6)
	bytes[0] = b.toBCD(uint8(t.Year() % 100)) // 年
	bytes[1] = b.toBCD(uint8(t.Month()))      // 月
	bytes[2] = b.toBCD(uint8(t.Day()))        // 日
	bytes[3] = b.toBCD(uint8(t.Hour()))       // 时
	bytes[4] = b.toBCD(uint8(t.Minute()))     // 分
	bytes[5] = b.toBCD(uint8(t.Second()))     // 秒
	return bytes
}

func (b *JT808MessageBuilder) toBCD(value uint8) byte {
	return ((value / 10) << 4) | (value % 10)
}

func (b *JT808MessageBuilder) padString(s string, length int) []byte {
	bytes := make([]byte, length)
	copy(bytes, []byte(s))
	return bytes
}

// ============================ 设备模拟器实现 ============================

// NewGPSDeviceSimulator 创建GPS设备模拟器
func NewGPSDeviceSimulator(terminalID, serverAddr, manufacturer string) *GPSDeviceSimulator {
	// 设置随机种子
	rand.Seed(time.Now().UnixNano())

	return &GPSDeviceSimulator{
		TerminalID:   terminalID,
		VehicleID:    "V" + terminalID,
		Manufacturer: manufacturer,
		ServerAddr:   serverAddr,
		CurrentLocation: Location{
			Latitude:  23.1291 + rand.Float64()*0.1, // 广州附近
			Longitude: 113.2644 + rand.Float64()*0.1,
			Speed:     40 + rand.Float64()*60, // 40-100 km/h
			Direction: rand.Float64() * 360,   // 0-360度
			Timestamp: time.Now(),
		},
	}
}

// Connect 连接到服务器
func (d *GPSDeviceSimulator) Connect() error {
	conn, err := net.Dial("tcp", d.ServerAddr)
	if err != nil {
		return err
	}

	d.Conn = conn
	d.IsConnected = true
	log.Printf("设备 %s 已连接到服务器 %s", d.TerminalID, d.ServerAddr)

	return nil
}

// StartSimulation 开始模拟
func (d *GPSDeviceSimulator) StartSimulation() {
	if !d.IsConnected {
		log.Printf("设备 %s 未连接，无法开始模拟", d.TerminalID)
		return
	}

	// 1. 发送注册消息
	d.sendRegisterMessage()

	// 2. 定时发送心跳
	go d.sendHeartbeats()

	// 3. 定时发送位置信息
	go d.sendLocationUpdates()
}

// sendRegisterMessage 发送注册消息
func (d *GPSDeviceSimulator) sendRegisterMessage() {
	builder := NewJT808MessageBuilder(d.TerminalID)
	message := builder.BuildRegisterMessage(d.Manufacturer, "GPS-Tracker-001")

	_, err := d.Conn.Write(message)
	if err != nil {
		log.Printf("设备 %s 发送注册消息失败: %v", d.TerminalID, err)
		return
	}

	log.Printf("设备 %s 发送注册消息成功", d.TerminalID)
}

// sendHeartbeats 定时发送心跳
func (d *GPSDeviceSimulator) sendHeartbeats() {
	ticker := time.NewTicker(60 * time.Second) // 每分钟一次心跳
	defer ticker.Stop()

	for d.IsConnected {
		<-ticker.C

		builder := NewJT808MessageBuilder(d.TerminalID)
		message := builder.BuildHeartbeatMessage()

		_, err := d.Conn.Write(message)
		if err != nil {
			log.Printf("设备 %s 发送心跳失败: %v", d.TerminalID, err)
			d.IsConnected = false
			return
		}

		log.Printf("设备 %s 发送心跳成功", d.TerminalID)
	}
}

// sendLocationUpdates 定时发送位置更新
func (d *GPSDeviceSimulator) sendLocationUpdates() {
	ticker := time.NewTicker(30 * time.Second) // 每30秒一次位置更新
	defer ticker.Stop()

	for d.IsConnected {
		<-ticker.C

		// 更新位置（模拟移动）
		d.updateLocation()

		builder := NewJT808MessageBuilder(d.TerminalID)
		message := builder.BuildLocationMessage(d.CurrentLocation, 0, 0) // 无报警，正常状态

		_, err := d.Conn.Write(message)
		if err != nil {
			log.Printf("设备 %s 发送位置信息失败: %v", d.TerminalID, err)
			d.IsConnected = false
			return
		}

		log.Printf("设备 %s 发送位置信息: 纬度=%.6f, 经度=%.6f, 速度=%.1fkm/h",
			d.TerminalID, d.CurrentLocation.Latitude, d.CurrentLocation.Longitude, d.CurrentLocation.Speed)
	}
}

// updateLocation 更新位置（模拟移动）
func (d *GPSDeviceSimulator) updateLocation() {
	// 简单的位置移动模拟
	distance := d.CurrentLocation.Speed / 120.0 // 30秒移动的距离（度）

	// 随机方向变化
	directionChange := (rand.Float64() - 0.5) * 10 // -5到5度的变化
	d.CurrentLocation.Direction += directionChange
	if d.CurrentLocation.Direction < 0 {
		d.CurrentLocation.Direction += 360
	}
	if d.CurrentLocation.Direction >= 360 {
		d.CurrentLocation.Direction -= 360
	}

	// 计算新的位置（简化版，实际应该使用球面三角学）
	rad := d.CurrentLocation.Direction * 3.14159265 / 180
	d.CurrentLocation.Latitude += distance * math.Cos(rad)
	d.CurrentLocation.Longitude += distance * math.Sin(rad)

	// 随机速度变化
	speedChange := (rand.Float64() - 0.5) * 20 // -10到10 km/h的变化
	d.CurrentLocation.Speed += speedChange
	if d.CurrentLocation.Speed < 0 {
		d.CurrentLocation.Speed = 0
	}
	if d.CurrentLocation.Speed > 120 {
		d.CurrentLocation.Speed = 120
	}

	d.CurrentLocation.Timestamp = time.Now()
}

// SendAlarm 发送报警消息
func (d *GPSDeviceSimulator) SendAlarm(alarmType uint32) {
	builder := NewJT808MessageBuilder(d.TerminalID)
	message := builder.BuildLocationMessage(d.CurrentLocation, alarmType, 0)

	_, err := d.Conn.Write(message)
	if err != nil {
		log.Printf("设备 %s 发送报警消息失败: %v", d.TerminalID, err)
		return
	}

	log.Printf("设备 %s 发送报警消息: 类型=0x%08X", d.TerminalID, alarmType)
}

// Disconnect 断开连接
func (d *GPSDeviceSimulator) Disconnect() {
	if d.Conn != nil {
		d.Conn.Close()
	}
	d.IsConnected = false
	log.Printf("设备 %s 已断开连接", d.TerminalID)
}

// ============================ 模拟器管理器实现 ============================

// NewSimulatorManager 创建模拟器管理器
func NewSimulatorManager() *SimulatorManager {
	return &SimulatorManager{
		simulators: make(map[string]*GPSDeviceSimulator),
	}
}

// AddSimulator 添加模拟器
func (m *SimulatorManager) AddSimulator(terminalID, serverAddr, manufacturer string) {
	m.mu.Lock()
	defer m.mu.Unlock()

	if _, exists := m.simulators[terminalID]; exists {
		log.Printf("模拟器 %s 已存在", terminalID)
		return
	}

	simulator := NewGPSDeviceSimulator(terminalID, serverAddr, manufacturer)
	m.simulators[terminalID] = simulator
	log.Printf("已添加设备模拟器: %s (%s)", terminalID, manufacturer)
}

// StartAllSimulators 启动所有模拟器
func (m *SimulatorManager) StartAllSimulators() {
	m.mu.RLock()
	defer m.mu.RUnlock()

	var wg sync.WaitGroup

	for id, simulator := range m.simulators {
		wg.Add(1)
		go func(s *GPSDeviceSimulator, terminalID string) {
			defer wg.Done()

			// 连接服务器
			if err := s.Connect(); err != nil {
				log.Printf("设备 %s 连接失败: %v", terminalID, err)
				return
			}

			// 开始模拟
			s.StartSimulation()

		}(simulator, id)

		// 避免同时连接过多设备
		time.Sleep(100 * time.Millisecond)
	}

	wg.Wait()
}

// StopAllSimulators 停止所有模拟器
func (m *SimulatorManager) StopAllSimulators() {
	m.mu.RLock()
	defer m.mu.RUnlock()

	for id, simulator := range m.simulators {
		simulator.Disconnect()
		log.Printf("设备 %s 已停止", id)
	}
}

// SendAlarm 发送报警
func (m *SimulatorManager) SendAlarm(terminalID string, alarmType uint32) {
	m.mu.RLock()
	defer m.mu.RUnlock()

	if simulator, exists := m.simulators[terminalID]; exists {
		simulator.SendAlarm(alarmType)
	} else {
		log.Printf("设备 %s 不存在", terminalID)
	}
}

// GetSimulator 获取模拟器
func (m *SimulatorManager) GetSimulator(terminalID string) *GPSDeviceSimulator {
	m.mu.RLock()
	defer m.mu.RUnlock()

	return m.simulators[terminalID]
}

// ============================ 主程序 ============================

func main() {
	log.Println("启动GPS设备808协议模拟器...")

	// 创建模拟器管理器
	manager := NewSimulatorManager()

	// 添加不同厂家的测试设备
	devices := []struct {
		terminalID   string
		manufacturer string
	}{
		{"13800138001", "manufacturer_a"}, // 厂家A设备
		{"13800138002", "manufacturer_a"},
		{"15800158001", "manufacturer_b"}, // 厂家B设备
		{"15800158002", "manufacturer_b"},
		{"13900139001", "default"}, // 默认厂家设备
	}

	serverAddr := "localhost:8081" // TCP服务器地址

	for _, device := range devices {
		manager.AddSimulator(device.terminalID, serverAddr, device.manufacturer)
	}

	// 启动模拟器
	go func() {
		time.Sleep(2 * time.Second) // 等待服务器启动
		log.Println("开始启动所有GPS设备模拟器...")
		manager.StartAllSimulators()
	}()

	// 模拟报警（可选）
	go func() {
		time.Sleep(30 * time.Second)
		log.Println("模拟紧急报警...")
		manager.SendAlarm("13800138001", 0x00000001) // 紧急报警

		time.Sleep(60 * time.Second)
		log.Println("模拟超速报警...")
		manager.SendAlarm("15800158001", 0x00000002) // 超速报警
	}()

	// 等待中断信号
	sigChan := make(chan os.Signal, 1)
	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)

	log.Println("GPS模拟器运行中... 按Ctrl+C停止")
	<-sigChan
	log.Println("接收到停止信号，正在关闭模拟器...")

	// 停止所有模拟器
	manager.StopAllSimulators()

	log.Println("GPS设备模拟器已停止")
}

// 辅助函数：打印使用说明
func printUsage() {
	fmt.Println("GPS设备808协议模拟器")
	fmt.Println("使用方法: go run main.go")
	fmt.Println("配置: 修改serverAddr变量来指定TCP服务器地址")
	fmt.Println("设备: 程序会自动创建5个测试设备连接到服务器")
}
